﻿using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using StandXunYouServer.IServices;
using StandXunYouServer.Model;
using StandXunYouServer.Utility;

namespace StandXunYouServer.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class LotteryController : ControllerBase
    {
        private readonly ILotteryServices _lotteryBase;

        private readonly ILogger<LotteryController> _logger;
        // 定义一个信号量，初始为1，最大为1（相当于互斥锁）
        private static readonly SemaphoreSlim _lotterySemaphore = new SemaphoreSlim(1, 1);

        public LotteryController(ILogger<LotteryController> logger, ILotteryServices lotteryBase)
        {
            _logger = logger;
            _lotteryBase = lotteryBase;
        }

        /// <summary>
        /// 获取全部奖品
        /// </summary>
        /// <returns></returns>
        [HttpGet("GetPrizesQueryAsync")]
        public async Task<IActionResult> GetPrizesQueryAsync()
        {
            try
            {
                var pList = await _lotteryBase.GetPrizesQueryAsync();

                return Ok(BaseState.CreateInstance(200, "请求成功", pList, pList.Count()));
            }
            catch (Exception ex)
            {
                _logger.LogError(ex.Message, "获取全部奖品失败");
            }
            return Ok(BaseState.CreateInstance(BaseState.RequestError, "请求服务器失败，请稍后重试"));
        }

        /// <summary>
        /// 获取用户所拥有的奖品
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        [HttpPost("GetByUserIdQueryAsync")]
        public async Task<IActionResult> GetByUserIdQueryAsync([FromForm] string userId)
        {
            try
            {
                var pList = await _lotteryBase.GetByUserIdQueryAsync(userId);

                return Ok(BaseState.CreateInstance(200, "请求成功", pList, pList.Count()));
            }
            catch (Exception ex)
            {
                _logger.LogError(ex.Message, "获取用户所拥有的奖品失败");
            }
            return Ok(BaseState.CreateInstance(BaseState.RequestError, "请求服务器失败，请稍后重试"));
        }

        /// <summary>
        /// 判断用户积分是否足够
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        [HttpGet("IsUserPointsAsync")]
        public async Task<IActionResult> IsUserPointsAsync(string userId)
        {
            try
            {
                var result = await _lotteryBase.IsUserPointsAsync(userId);

                return Ok(BaseState.CreateInstance(200, "请求成功", result));
            }
            catch (Exception ex)
            {
                _logger.LogError(ex.Message, "判断用户积分是否足够失败");
            }
            return Ok(BaseState.CreateInstance(BaseState.RequestError, "请求服务器失败，请稍后重试"));
        }

        /// <summary>
        /// 开始抽奖
        /// </summary>
        /// <returns></returns>
        [HttpPost("StartLotteryAsync")]
        public async Task<IActionResult> StartLotteryAsync([FromForm] string userId)
        {
            /*先让该线程执行，其他线程等待 为什么需要这一步？如果有多个人同时抽到了同一个奖品，而该奖品的数量只有一个，
              得不到奖品的用户则会收到：“服务器繁忙请稍后重试！”*/
            await _lotterySemaphore.WaitAsync();
            try
            {
                Prizes pModel = new Prizes();
                var isSuccess = false;

                //获取到所有奖品（数量不为 0的）
                var pList = await _lotteryBase.GetPrizesIsZeroQueryAsync();
                //随机生成一个随机数
                var random = new Random().Next(1, 100);

                switch (random)
                {
                    case 1:  //概率为1%的奖品
                        pModel = pList.Where(x => x.PrizeProbability == 1).First();
                        //写入用户奖品
                        isSuccess = await InsertUserPrizeAsync(userId, pModel.PrizeId);
                        break;
                    case int n when (n > 1 && n <= 20):  //概率为20%的奖品
                        pModel = pList.Where(x => x.PrizeProbability > 1 && x.PrizeProbability <= 20).First();
                        isSuccess = await InsertUserPrizeAsync(userId, pModel.PrizeId);
                        break;
                    case int n when (n > 20 && n <= 50):  //概率为30%的奖品
                        pModel = pList.Where(x => x.PrizeProbability > 20 && x.PrizeProbability <= 50).First();
                        isSuccess = await InsertUserPrizeAsync(userId, pModel.PrizeId);
                        break;
                    case int n when (n > 50 && n <= 100):  //概率大于50%的奖品

                        //可能有如下要求：50%概率以下的奖品为固定的，而往上的则为多个奖品占据剩下的概率
                        var pNewList = pList.Where(x => x.PrizeProbability > 50).ToList();
                        if (pNewList.Any()) //判断是否存在元素
                        {
                            Random newRandom = new Random();
                            pModel = pNewList.OrderBy(x => newRandom.Next()).First(); //随机获取一个奖品
                            isSuccess = await InsertUserPrizeAsync(userId, pModel.PrizeId);
                        }
                        break;
                }

                if (isSuccess)
                    return Ok(BaseState.CreateInstance(200, "请求成功！", pModel.PrizeName));
            }
            catch (Exception ex)
            {
                _logger.LogError(ex.Message, "用户抽奖失败");
            }
            finally //无论是否异常都会执行
            {
                _lotterySemaphore.Release();
            }

            return Ok(BaseState.CreateInstance(BaseState.RequestError, "请求服务器失败，请稍后重试"));
        }

        /// <summary>
        /// 减少用户积分、奖品数量并为添加用户奖品
        /// </summary>
        /// <param name="userId">用户Id</param>
        /// <param name="prizeId">奖品Id</param>
        /// <returns></returns>
        [NonAction]
        public async Task<bool> InsertUserPrizeAsync(string userId, string prizeId) 
        {
            bool isSuccess = false;
            try
            {
                UserPrize upModel = new UserPrize() {
                    Id = Guid.NewGuid().ToString(),
                    UserId = userId,
                    PrizeId = prizeId
                };

                isSuccess = await _lotteryBase.UpdatePointsPrizeCountAndInsertUserPrizeAsync(userId, upModel);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex.Message, "为奖品表添加数据失败");
            }
            return isSuccess;
        }

    }
}
